import("stdfaust.lib");

//-------------------------`windchimes`-----------------------
// windchimes(wind) : simulates five windchimes in the wind
//
// #### Usage
//
// ```
// windchimes(wind) : _
// ```
//
// Where:
//
// * `wind`: the wind strength in the range 0-2
//
// #### Examples
//
// ```
// windchimes(wind) <: (_, _);
// ```
//
//------------------------------------------------------------

N = 5;

delay(t, d) = a : edge
    with
    {
        dd = d : ba.sAndH(t);
        a = en.ar(dd / 1000, 0, t);
        edge(s) = (s' != 0) & (s == 0); 
    };

rnd_trig = out
    with {
        rnd_ms(t) = no.noise : +(1) : /(2) : *(20) : +(30) : ba.sAndH(t);
        kick = 1 - (1 : mem); 
        out = (+(kick) <: (_, rnd_ms) : delay) ~ (_);
    };

state(n, p, t) = ba.if(r <= (p / 2), s_up(n), ba.if(r <= p, s_down(n), 0))
    with {
        r = no.noise : abs : ba.sAndH(t);
        s_down(n) = ba.if(n == 1, N, n - 1);
        s_up(n) = ba.if(n == N, 1, n + 1);
    };

state0(p, t) = ba.if(r <= p, round((r / p) * (N - 1)) + 1, 0)
    with {
        r = no.noise : abs : ba.sAndH(t);
    };

model(p, t) = states ~ (mem)
    with {
        trigbus(j) = t : ba.selectoutn(N + 1, j);
        prob = p : ba.sAndH(t) <: si.bus(N + 1);
        latched(j) = j : ba.sAndH(t);
        states(j) = (prob, trigbus(latched(j))) : ro.interleave((N + 1), 2) : state0, par(i, N, state(i + 1)) : ba.selectn(N + 1, latched(j));
    };

energy(w) = En ~ (mem)
    with {
        Rdec = 0.99997;
        ts = 1 / ma.SR;
        dn = ts * w;
        En(ep) = Rdec * (dn + ep);
    };

hit_prob(e) = 1.0 / (1 + (99 * exp(-2 * e)));

burst(e, t) = no.noise : *(env) 
    with {
        es = e : ba.sAndH(t);
        env = pow(0.97, 1000 * (1 - en.ar(0.0, 0.02, t))) * a;
        a = sqrt(es + 0.1);
    };

tube(fs, e, t) = burst(e, t) <: fs :> _;

tube1 = tube(
    (
        fi.iir((0.004528016647259483, 0.0, -0.004528016647259483), (-1.9991578581495515, 0.9999856089467211)),
        fi.iir((0.028540057030698885, 0.0, -0.028540057030698885), (-1.9939523343007244, 0.9999177681993272)),
        fi.iir((0.290932916859811, 0.0, -0.290932916859811), (-1.9784354709624337, 0.999712218280481)),
        fi.iir((0.0062308445773086975, 0.0, -0.0062308445773086975), (-1.9462261852132052, 0.9994245193792802)),
        fi.iir((0.017763702884906595, 0.0, -0.017763702884906595), (-1.8915978844912849, 0.9988493699365051))
    )
);

tube2 = tube(
    (
        fi.iir((0.0050634577165950085, 0.0, -0.0050634577165950085), (-1.998950465658379, 0.9999856089467211)),
        fi.iir((0.031791650109211915, 0.0, -0.031791650109211915), (-1.9925129392788863, 0.9999177681993272)),
        fi.iir((0.3229546018475371, 0.0, -0.3229546018475371), (-1.9734612234415767, 0.999712218280481)),
        fi.iir((0.006884051095076797, 0.0, -0.006884051095076797), (-1.9342904838598312, 0.9994245193792802)),
        fi.iir((0.01951809943698988, 0.0, -0.01951809943698988), (-1.868596773968664, 0.9988493699365051))
    )
);

tube3 = tube(
    (
        fi.iir((0.0060538644527733665, 0.0, -0.0060538644527733665), (-1.9985057518687033, 0.9999856089467211)),
        fi.iir((0.03780568150590768, 0.0, -0.03780568150590768), (-1.9894383400427211, 0.9999177681993272)),
        fi.iir((0.38118631352242155, 0.0, -0.38118631352242155), (-1.9630450505565107, 0.999712218280481)),
        fi.iir((0.00810371600245871, 0.0, -0.00810371600245871), (-1.908572035471357, 0.9994245193792802)),
        fi.iir((0.02287443857794636, 0.0, -0.02287443857794636), (-1.8175561022180358, 0.9988493699365051))
    )
);

tube4 = tube(
    (
        fi.iir((0.006829963406716232, 0.0, -0.006829963406716232), (-1.998101807980611, 0.9999856089467211)),
        fi.iir((0.042285628336654155, 0.0, -0.042285628336654155), (-1.9867988979110907, 0.9999177681993272)),
        fi.iir((0.4242091090450038, 0.0, -0.4242091090450038), (-1.9541994546750083, 0.999712218280481)),
        fi.iir((0.008998045088023305, 0.0, -0.008998045088023305), (-1.8867845176260951, 0.9994245193792802)),
        fi.iir((0.025301978185301294, 0.0, -0.025301978185301294), (-1.7745042678183585, 0.9988493699365051))
    )
);

tube5 = tube(
    (
        fi.iir((0.0075400413038973855, 0.0, -0.0075400413038973855), (-1.9976895105377712, 0.9999856089467211)),
        fi.iir((0.04670647689695959, 0.0, -0.04670647689695959), (-1.9839007786365699, 0.9999177681993272)),
        fi.iir((0.46534722669369927, 0.0, -0.46534722669369927), (-1.9448138307342515, 0.999712218280481)),
        fi.iir((0.009847739572905198, 0.0, -0.009847739572905198), (-1.863700481873562, 0.9994245193792802)),
        fi.iir((0.027578232028705636, 0.0, -0.027578232028705636), (-1.7290749312918612, 0.9988493699365051))
    )
);

windchimes(wind) = sel
    with {
        en = energy(wind) : hbargraph("v:wind chimes/energy", 0, 1.5);
        prob = hit_prob(en) : hbargraph("v:wind chimes/hit probability", 0, 1.0);
        state = model(prob, rnd_trig);
        hit_trig = state != state';
        tubes = tube1(en, hit_trig);
        sel = hit_trig : ba.selectoutn(N + 1, state) : (si.block(1), si.bus(N)):
            (tube1(en), tube2(en), tube3(en), tube4(en), tube5(en)) :> *(0.25);
    };

process = windchimes(wind) <: (_, _)
    with {
        wind = hslider("v:wind chimes/wind", 0.0, 0, 2, 0.01);
    };

